Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ziga/add personal sign authentication message #1811

Merged
merged 21 commits into from
Mar 18, 2024

Conversation

zkokelj
Copy link
Contributor

@zkokelj zkokelj commented Feb 21, 2024

Why this change is needed

We want to use Rainbowkit (https://www.rainbowkit.com/) in the future and they don't support EIP-712 messages yet.
To use them we need to add personal sign message, because it is impossible to overwrite signer there.
In order to avoid confusion I also refactored and simplified parts of code for signature verification and introduced signatureType.

What changes were made as part of this PR

  • Added new personal sign message and methods to verify it.
  • Refactored code around verifying signatures
  • Added signature type
  • Refactored viewing key tests

PR checks pre-merging

Please indicate below by ticking the checkbox that you have read and performed the required
PR checks

  • PR checks reviewed and performed

@zkokelj zkokelj marked this pull request as ready for review February 22, 2024 11:55
@zkokelj zkokelj force-pushed the ziga/add_personal_sign_authentication_message branch from 7c02e15 to 1976388 Compare February 22, 2024 15:13
go/common/viewingkey/viewing_key.go Outdated Show resolved Hide resolved
@zkokelj zkokelj force-pushed the ziga/add_personal_sign_authentication_message branch 2 times, most recently from 47cbbb3 to 2c1f41c Compare March 5, 2024 10:23
@zkokelj zkokelj force-pushed the ziga/add_personal_sign_authentication_message branch from f148e94 to c2f85ed Compare March 13, 2024 14:37
Copy link
Collaborator

@tudor-malene tudor-malene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks Ziga. Much better now.
A few improvements and this should be good to merge

var PersonalSignMessageSupportedVersions = []int{1}

// SignatureType is used to differentiate between different signature types (string is used, because int is not RLP-serializable)
type SignatureType string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can make SignatureType an iota to avoid the conversions and minimize the data

Copy link
Contributor Author

@zkokelj zkokelj Mar 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was my initial approach, but having SignatureType of type int causes problems with RLP serialisation.
And errors like this:

Cause: rlp: type int is not RLP-serializable (struct field viewingkey.RPCSignedViewingKey.SignatureType) (struct field common.LogSubscription.ViewingKey)"}} component=test_log

I can change it to []byte to save some space. What do you think? Do you have some other ideas?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about int8 or one of the other int types?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all int types fail with the same error unfortunately

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about uints?

@@ -245,8 +274,8 @@ func CheckSignatureAndReturnAccountAddress(hashBytes []byte, signature []byte) (
return nil, fmt.Errorf("invalid signature")
}

// CheckEIP712Signature checks if signature is valid for provided userID and chainID and return address or nil if not valid
func CheckEIP712Signature(userID string, signature []byte, chainID int64) (*gethcommon.Address, error) {
// checkEIP712Signature checks if signature is valid for provided userID and chainID and return address or nil if not valid
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be nice if these functions each lived in their own type behind an interface

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

func CheckSignature(encryptionToken string, signature []byte, chainID int64, signatureType SignatureType) (*gethcommon.Address, error) {
if signatureType == PersonalSign {
return checkPersonalSignSignature(encryptionToken, signature, chainID)
} else if signatureType == EIP712Signature {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if these checks were each in their type, then you can have a map of registered signature handlers, and make this method much simpler

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

func (o *TGLib) RegisterAccountPersonalSign(pk *ecdsa.PrivateKey, addr gethcommon.Address) error {
// create the registration message
personalSignMessage := viewingkey.GeneratePersonalSignMessage(string(o.userID), integration.TenChainID, 1)
prefixedMessage := fmt.Sprintf(viewingkey.PersonalSignMessagePrefix, len(personalSignMessage), personalSignMessage)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this prefix logic be in the GeneratePersonalSignMessage function as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Actually this prefixing can be removed by using accounts.TextHash from geth, which adds the prefix and hashes the message + keeping it without a prefix is better for the new endpoints (wallets like Metamask automatically adds this prefix to the message)

@zkokelj
Copy link
Contributor Author

zkokelj commented Mar 14, 2024

General comment / question.

Is it critical if our system is vulnerable to the following (possible attack)?

When users sign the message to authenticate them they have 3 options (legacy will be removed and I won't talk about it).
personalSign and EIP712Sign. This is used to prove, that they are actually the owners of that account.
But if user sends the signature to the node and sets the message type to the other type the node "thinks" that it is another address and does not detect that. To be able to detect that we would need to include messageHash with the signature.
What do you think @tudor-malene ?

@tudor-malene
Copy link
Collaborator

General comment / question.

Is it critical if our system is vulnerable to the following (possible attack)?

When users sign the message to authenticate them they have 3 options (legacy will be removed and I won't talk about it). personalSign and EIP712Sign. This is used to prove, that they are actually the owners of that account. But if user sends the signature to the node and sets the message type to the other type the node "thinks" that it is another address and does not detect that. To be able to detect that we would need to include messageHash with the signature. What do you think @tudor-malene ?

If I understand the attack correctly, the user wants to read the data of an account they don't control. For this, they have to produce a signed message of one of the 2 formats that contains the target address in the right place and sign that with a key they control that somehow, when going through our recovery algorithm will produce the right values?

Copy link
Collaborator

@tudor-malene tudor-malene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks Ziga. I think it looks good now. The responsibilities are quite clear.
One last thing to check if other int data types work for the type .

var PersonalSignMessageSupportedVersions = []int{1}

// SignatureType is used to differentiate between different signature types (string is used, because int is not RLP-serializable)
type SignatureType string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about int8 or one of the other int types?

SignatureType SignatureType
}

// SignatureChecker is an interface for checking if signature is valid for provided encryptionToken and chainID and return address or nil if not valid
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return "signing address"

Copy link
Collaborator

@tudor-malene tudor-malene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@zkokelj zkokelj merged commit a38b4ab into main Mar 18, 2024
2 checks passed
@zkokelj zkokelj deleted the ziga/add_personal_sign_authentication_message branch March 18, 2024 11:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants